#pragma once

using namespace System;

delegate void GlobalPrintDelegate(int i);

static void GlobalStaticPrint(int i)
{
	System::Console::WriteLine("GlobalStaticPrint:");
	System::Console::WriteLine(i);
}

void GlobalPrint(int i)
{
	System::Console::WriteLine("GlobalPrint:");
	System::Console::WriteLine(i);
}

ref class DelegateTestRC
{
public:
	DelegateTestRC(){}
	~DelegateTestRC(){}

	delegate void PrintDelegate(int i);

	static void Print1(int i)
	{
		System::Console::WriteLine("DelegateTestRC::StaticPrint1:");
		System::Console::WriteLine(i);
	}

	void Print2(int i)
	{
		System::Console::WriteLine("DelegateTestRC::Print2:");
		System::Console::WriteLine(i);
	}

	void Test()
	{
		PrintDelegate^ d;
		d += gcnew PrintDelegate(&GlobalPrint);
		d += gcnew PrintDelegate(&GlobalStaticPrint);
		d += gcnew PrintDelegate(&Print1);
		d += gcnew PrintDelegate(this, &DelegateTestRC::Print2);
		d += gcnew PrintDelegate(this, &DelegateTestRC::Print2);
		d(10);

		d -= gcnew PrintDelegate(&Print1);
		d -= gcnew PrintDelegate(this, &DelegateTestRC::Print2);
		d(20);
	}
};


void GlobalTest()
{
	GlobalPrintDelegate^ d;
	d += gcnew GlobalPrintDelegate(&GlobalPrint);
	d += gcnew GlobalPrintDelegate(&GlobalStaticPrint);
	d += gcnew GlobalPrintDelegate(&DelegateTestRC::Print1);
	d += gcnew GlobalPrintDelegate(gcnew DelegateTestRC(), &DelegateTestRC::Print2);
	d(30);

	DelegateTestRC::PrintDelegate^ d1;
	d1 += gcnew DelegateTestRC::PrintDelegate(&GlobalPrint);
	d1 += gcnew DelegateTestRC::PrintDelegate(&GlobalStaticPrint);
	d1 += gcnew DelegateTestRC::PrintDelegate(&DelegateTestRC::Print1);
	d1 += gcnew DelegateTestRC::PrintDelegate(gcnew DelegateTestRC(), &DelegateTestRC::Print2);
	d1(40);
}


void OtherTest()
{
	GlobalPrintDelegate^ gd1 = gcnew GlobalPrintDelegate(&GlobalPrint);
	GlobalPrintDelegate^ gd2 = gcnew GlobalPrintDelegate(&DelegateTestRC::Print1);

	GlobalPrintDelegate^ gd3 = gd1 + gd2;
	gd3(50);

	GlobalPrintDelegate^ gd4 = gd3 - gd1;
	gd4(60);

	DelegateTestRC::PrintDelegate^ d = nullptr;
	//// error : crash if nullptr
	//d(70);

	//// error: different delegate type
	//d = gd1;
}


ref struct DelegateTestRS
{
public:
	delegate void PrintDelegate();
};

value class DelegateTestVC
{
public:
	delegate void PrintDelegate();
};

value struct DelegateTestVS
{
public:
	delegate void PrintDelegate();
};

//// error : delegate cannot declare in an unmanaged class or struct
//class DelegateTestC
//{
//public:
//	delegate void PrintDelegate();
//};

//struct DelegateTestS
//{
//public:
//	delegate void PrintDelegate();
//};
